﻿/* PRQA S 3108++ */
/**
 * Copyright (C) 2024 Isoft Infrastructure Software Co., Ltd.
 * SPDX-License-Identifier: LGPL-2.1-only-with-exception OR  LicenseRef-Commercial-License
 *
 * This library is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation; version 2.1.
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License along with this library;
 * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 * or see <https://www.gnu.org/licenses/>.
 *
 * Alternatively, this file may be used under the terms of the Isoft Infrastructure Software Co., Ltd.
 * Commercial License, in which case the provisions of the Isoft Infrastructure Software Co., Ltd.
 * Commercial License shall apply instead of those of the GNU Lesser General Public License.
 *
 * You should have received a copy of the Isoft Infrastructure Software Co., Ltd.  Commercial License
 * along with this program. If not, please find it at <https://EasyXMen.com/xy/reference/permissions.html>
 *
 ********************************************************************************
 **                                                                            **
 **  FILENAME    : sm2_alg.c                                                    **
 **                                                                            **
 **  Created on  :                                                             **
 **  Author      : For the world peace                                         **
 **  Vendor      :                                                             **
 **  DESCRIPTION : Implementation for SM2 crypto algorithm                     **
 **                                                                            **
 **  SPECIFICATION(S):   AUTOSAR classic Platform 4.4.0                       **
 **                                                                            **
 *******************************************************************************/
/* PRQA S 3108-- */
/*******************************************************************************
**                      Includes                                              **
*******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include "sm2.h"
#include "sm2_common.h"

/*******************************************************************************
**                      Private Macro Definitions                             **
*******************************************************************************/

/*******************************************************************************
**                      Private Type Definitions                              **
*******************************************************************************/

/*******************************************************************************
**                      Private Function Declarations                         **
*******************************************************************************/

static int peace_sm2_bn288_cmp(const uint64_t a[9], const uint64_t b[9]);
static void peace_sm2_bn288_add(uint64_t r[9], const uint64_t a[9], const uint64_t b[9]);
static void peace_sm2_bn288_sub(uint64_t ret[9], const uint64_t a[9], const uint64_t b[9]);

/*******************************************************************************
**                      Private Variable Definitions                          **
*******************************************************************************/
static const peace_sm2_BN peace_sm2_P = {
    0xffffffffu,
    0xffffffffu,
    0x00000000u,
    0xffffffffu,
    0xffffffffu,
    0xffffffffu,
    0xffffffffu,
    0xfffffffeu,
};

static const peace_sm2_BN peace_sm2_B = {
    0x4d940e93u,
    0xddbcbd41u,
    0x15ab8f92u,
    0xf39789f5u,
    0xcf6509a7u,
    0x4d5a9e4bu,
    0x9d9f5e34u,
    0x28e9fa9eu,
};



static uint64_t s_mul[16] = {0};
static uint64_t u = 0;
static uint64_t w = 0;
static peace_sm2_BN tmp={0};
static peace_sm2_BN a1, a2, a3, a4, a5;
// static peace_sm2_BN _x, _y, _g, _z;

static peace_sm2_BN d = {0};
static char bits[257] = {0};
static uint64_t c[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0x100000000};
static peace_sm2_BN t0;
static peace_sm2_BN t1;
static peace_sm2_BN t2;
static peace_sm2_BN T1;
static peace_sm2_BN T2;
static peace_sm2_BN T3;
// static peace_sm2_BN X3;
// static peace_sm2_BN Y3;
// static peace_sm2_BN Z3;
static peace_sm2_BN z_inv;

static peace_sm2_BN T1_Add;
static peace_sm2_BN T2_Add;
static peace_sm2_BN T3_Add;
static peace_sm2_BN T4_Add;
// static peace_sm2_BN X3_Add;
// static peace_sm2_BN Y3_Add;
// static peace_sm2_BN Z3_Add;
static peace_sm2_BN point_x;
static peace_sm2_BN point_y;

static peace_sm2_JACOBIAN_POINT _T, *T = &_T;
// static peace_sm2_JACOBIAN_POINT _Q;
static peace_sm2_JACOBIAN_POINT _sG, *sG = &_sG;
// static peace_sm2_JACOBIAN_POINT T_CURVE;
static peace_sm2_JACOBIAN_POINT _Q_ADD, *Q_ADD = &_Q_ADD;
/*******************************************************************************
**                      Global Variable Definitions                          **
*******************************************************************************/
const peace_sm2_JACOBIAN_POINT peace_sm2_G = {
    {
        0x334c74c7u,
        0x715a4589u,
        0xf2660be1u,
        0x8fe30bbfu,
        0x6a39c994u,
        0x5f990446u,
        0x1f198119u,
        0x32c4ae2cu,
    },
    {
        0x2139f0a0u,
        0x02df32e5u,
        0xc62a4740u,
        0xd0a9877cu,
        0x6b692153u,
        0x59bdcee3u,
        0xf4f6779cu,
        0xbc3736a2u,
    },
    {
        1u,
        0u,
        0u,
        0u,
        0u,
        0u,
        0u,
        0u,
    },
};
const peace_sm2_JACOBIAN_POINT *peace_sm2_G_ptr = &peace_sm2_G;
const peace_sm2_BN peace_sm2_N = {
    0x39d54123u,
    0x53bbf409u,
    0x21c6052bu,
    0x7203df6bu,
    0xffffffffu,
    0xffffffffu,
    0xffffffffu,
    0xfffffffeu,
};

const peace_sm2_BN peace_sm2_ONE = {1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u};
// const peace_sm2_BN peace_sm2_TWO = {2u, 0u, 0u, 0u, 0u, 0u, 0u, 0u};
const peace_sm2_BN peace_sm2_THREE = {3u, 0u, 0u, 0u, 0u, 0u, 0u, 0u};

/*******************************************************************************
**                      Global Function Definitions                           **
*******************************************************************************/

/**
 * @brief Converts a big number to a byte array.
 *
 * This function converts the given big number `a` into a 32-byte array `out`.
 * The conversion is done in big-endian order.
 *
 * @param[in] a   Big number to be converted.
 * @param[out] out Output byte array of length 32.
 */
void peace_sm2_bn_to_bytes(const peace_sm2_BN a, uint8 out[32])
{
    int i;
    for (i = 7; i >= 0; i--)
    {
        uint32 ai = (uint32)a[i];
        PUTU32(out, ai);
        out += sizeof(uint32);
    }
}

/**
 * @brief Converts a big number to a binary string of bits.
 *
 * This function converts the given big number `a` into a binary string `bits`.
 *
 * @param[in] a   Big number to be converted.
 * @param[out] bits Output binary string of length 256.
 */
void peace_sm2_bn_to_bits(const peace_sm2_BN a, char bits[256])
{
    int i, j;
    uint64_t w;
    for (i = 7; i >= 0; i--)
    {
        w = a[i];
        for (j = 0; j < 32; j++)
        {
            *bits++ = (w & 0x80000000) ? '1' : '0';
            w <<= 1;
        }
    }
}

/**
 * @brief Performs a right shift operation on a big number.
 *
 * This function performs a right shift operation on the given big number `a` by `nbits` bits.
 *
 * @param[out] ret Resulting big number after the shift.
 * @param[in] a   Big number to shift.
 * @param[in] nbits Number of bits to shift.
 * @return 1 on success, E_ERROR on failure.
 */
int peace_sm2_bn_rshift(peace_sm2_BN ret, const peace_sm2_BN a, unsigned int nbits)
{
    // peace_sm2_BN r;
    int i;

    if (nbits > 31)
    {
        return E_ERROR;
    }
    if (nbits == 0)
    {
        memcpy(ret, a, PEACE_SM2_sizeof_bn);
    }

    for (i = 0; i < 7; i++)
    {
        ret[i] = a[i] >> nbits;
        ret[i] |= (a[i + 1] << (32 - nbits)) & 0xffffffffu;
    }
    ret[i] = a[i] >> nbits;
    //(void)ILib_memcpy(ret, ret, PEACE_SM2_sizeof_bn);
    return 1;
}
/**
 * @brief Generates a random big number within a specified range.
 *
 * This function generates a random big number `r` that is less than `range`.
 *
 * @param[out] r  Resulting random big number.
 * @param[in] range Upper bound for the random number.
 * @return 1 on success, E_ERROR on failure.
 */
int peace_sm2_bn_rand_range(peace_sm2_BN r, const peace_sm2_BN range)
{
    uint8_t buf[32];
    do
    {
        srand(time((void *)0));
        for (int a = 0; a < sizeof(buf); a++)
        {
            buf[a] = rand() % 255;
        }

        peace_sm2_bn_from_bytes(r, buf);
    } while (peace_sm2_bn_cmp(r, range) >= 0);
    return 1;
}
/**
 * @brief Subtracts two finite field elements.
 *
 * This function subtracts finite field element `b` from `a` and stores the result in `r`.
 *
 * @param[out] r  Resulting finite field element.
 * @param[in] a   First finite field element.
 * @param[in] b   Second finite field element.
 */
void peace_sm2_fp_sub(peace_sm2_Fp r, const peace_sm2_Fp a, const peace_sm2_Fp b)
{
    if (peace_sm2_bn_cmp(a, b) >= 0)
    {
        peace_sm2_bn_sub(r, a, b);
    }
    else
    {
        // peace_sm2_BN t;
        peace_sm2_bn_sub(tmp, peace_sm2_P, b);
        peace_sm2_bn_add(r, tmp, a);
    }
}

/**
 * @brief Divides a finite field element by 2.
 *
 * This function divides the given finite field element `a` by 2 and stores the result in `r`.
 *
 * @param[out] r  Resulting finite field element.
 * @param[in] a   Finite field element to divide.
 */
void peace_sm2_fp_div2(peace_sm2_Fp r, const peace_sm2_Fp a)
{
    int i;
    memcpy(r, a, PEACE_SM2_sizeof_bn);
    if (r[0] & 0x01)
    {
        peace_sm2_bn_add(r, r, peace_sm2_P);
    }
    for (i = 0; i < 7; i++)
    {
        r[i] = (r[i] >> 1) | (uint64_t)((r[i + 1] & 0x01) << 31);
    }
    r[i] >>= 1;
}

/**
 * @brief Negates a finite field element.
 *
 * This function negates the given finite field element `a` and stores the result in `r`.
 *
 * @param[out] r  Resulting finite field element.
 * @param[in] a   Finite field element to negate.
 */
void peace_sm2_fp_neg(peace_sm2_Fp r, const peace_sm2_Fp a)
{
    if (peace_sm2_bn_is_zero(a))
    {
        memcpy(r, a, PEACE_SM2_sizeof_bn);
    }
    else
    {
        peace_sm2_bn_sub(r, peace_sm2_P, a);
    }
}

/**
 * @brief Multiplies two finite field elements.
 *
 * This function multiplies two finite field elements `a` and `b` and stores the result in `r`.
 *
 * @param[out] r  Resulting finite field element.
 * @param[in] a   First finite field element.
 * @param[in] b   Second finite field element.
 */

void peace_sm2_fp_mul(peace_sm2_Fp r, const peace_sm2_Fp a, const peace_sm2_Fp b)
{
    int i, j;

    // peace_sm2_BN d = {0};
    // uint64_t u;
    for (i = 0; i < 16; i++)
    {
        s_mul[i] = 0;
    }
    for (i = 0; i < 8; i++)
    {
        u = 0;
        for (j = 0; j < 8; j++)
        {

        	u = (uint64_t)(s_mul[i + j] + (uint64_t)(a[i] * b[j]) + u);
            s_mul[i + j] = (uint64_t)(u & 0xffffffffu);
            u =  (uint64_t)((u>> 32)& 0xffffffffu);
        }
        s_mul[i + 8] = u;
    }

    r[0] = s_mul[0] + s_mul[8] + s_mul[9] + s_mul[10] + s_mul[11] + s_mul[12] + (uint64_t)((s_mul[13] + s_mul[14] + s_mul[15]) << 1);
    r[1] = s_mul[1] + s_mul[9] + s_mul[10] + s_mul[11] + s_mul[12] + s_mul[13] + (uint64_t)((s_mul[14] + s_mul[15]) << 1);
    r[2] = s_mul[2];
    r[3] = s_mul[3] + s_mul[8] + s_mul[11] + s_mul[12] + s_mul[14] + s_mul[15] + (uint64_t)(s_mul[13] << 1);
    r[4] = s_mul[4] + s_mul[9] + s_mul[12] + s_mul[13] + s_mul[15] + (uint64_t)(s_mul[14] << 1);
    r[5] = s_mul[5] + s_mul[10] + s_mul[13] + s_mul[14] + (uint64_t)(s_mul[15] << 1);
    r[6] = s_mul[6] + s_mul[11] + s_mul[14] + s_mul[15];
    r[7] = s_mul[7] + s_mul[8] + s_mul[9] + s_mul[10] + s_mul[11] + s_mul[15] + (uint64_t)((s_mul[12] + s_mul[13] + s_mul[14] + s_mul[15]) << 1);

    for (i = 1; i < 8; i++)
    {
        r[i] += (uint64_t)((r[i - 1] >> 32) & 0xffffffffu);
        r[i - 1] &= 0xffffffffu;
    }

    d[2] = s_mul[8] + s_mul[9] + s_mul[13] + s_mul[14];
    d[3] = (uint64_t)((d[2] >> 32) & 0xffffffffu);
    d[2] &= 0xffffffffu;
    peace_sm2_bn_sub(r, r, d);

    while (peace_sm2_bn_cmp(r, peace_sm2_P) >= 0)
    {
        peace_sm2_bn_sub(r, r, peace_sm2_P);
    }
}



/**
 * @brief Computes the modular inverse of a and stores the result in r.
 * @param[in,out] r The result of the modular inverse of a, passed as an output parameter.
 * @param[in] a The input for which the modular inverse is computed.
 */
void peace_sm2_fp_inv(peace_sm2_Fp r, const peace_sm2_Fp a)
{

    int i;

    // Intermediate calculations for the modular inverse
    for (i = 0; i < 8; i++)
    {
        a1[i] = 0;
        a2[i] = 0;
        a3[i] = 0;
        a4[i] = 0;
        a5[i] = 0;
    }

    peace_sm2_fp_mul(a1, a, a);
    peace_sm2_fp_mul(a2, a1, a);
    peace_sm2_fp_mul(a3, a2, a2);
    peace_sm2_fp_mul(a3, a3, a3);
    peace_sm2_fp_mul(a3, a3, a2);
    peace_sm2_fp_mul(a4, a3, a3);
    peace_sm2_fp_mul(a4, a4, a4);
    peace_sm2_fp_mul(a4, a4, a4);
    peace_sm2_fp_mul(a4, a4, a4);
    peace_sm2_fp_mul(a4, a4, a3);
    peace_sm2_fp_mul(a5, a4, a4);
    for (i = 1; i < 8; i++)
        peace_sm2_fp_mul(a5, a5, a5);
    peace_sm2_fp_mul(a5, a5, a4);
    for (i = 0; i < 8; i++)
        peace_sm2_fp_mul(a5, a5, a5);
    peace_sm2_fp_mul(a5, a5, a4);
    for (i = 0; i < 4; i++)
        peace_sm2_fp_mul(a5, a5, a5);
    peace_sm2_fp_mul(a5, a5, a3);
    peace_sm2_fp_mul(a5, a5, a5);
    peace_sm2_fp_mul(a5, a5, a5);
    peace_sm2_fp_mul(a5, a5, a2);
    peace_sm2_fp_mul(a5, a5, a5);
    peace_sm2_fp_mul(a5, a5, a);
    peace_sm2_fp_mul(a4, a5, a5);
    peace_sm2_fp_mul(a3, a4, a1);
    peace_sm2_fp_mul(a5, a4, a4);
    for (i = 1; i < 31; i++)
        peace_sm2_fp_mul(a5, a5, a5);
    peace_sm2_fp_mul(a4, a5, a4);
    peace_sm2_fp_mul(a4, a4, a4);
    peace_sm2_fp_mul(a4, a4, a);
    peace_sm2_fp_mul(a3, a4, a2);
    for (i = 0; i < 33; i++)
        peace_sm2_fp_mul(a5, a5, a5);
    peace_sm2_fp_mul(a2, a5, a3);
    peace_sm2_fp_mul(a3, a2, a3);
    for (i = 0; i < 32; i++)
        peace_sm2_fp_mul(a5, a5, a5);
    peace_sm2_fp_mul(a2, a5, a3);
    peace_sm2_fp_mul(a3, a2, a3);
    peace_sm2_fp_mul(a4, a2, a4);
    for (i = 0; i < 32; i++)
        peace_sm2_fp_mul(a5, a5, a5);
    peace_sm2_fp_mul(a2, a5, a3);
    peace_sm2_fp_mul(a3, a2, a3);
    peace_sm2_fp_mul(a4, a2, a4);
    for (i = 0; i < 32; i++)
        peace_sm2_fp_mul(a5, a5, a5);
    peace_sm2_fp_mul(a2, a5, a3);
    peace_sm2_fp_mul(a3, a2, a3);
    peace_sm2_fp_mul(a4, a2, a4);
    for (i = 0; i < 32; i++)
        peace_sm2_fp_mul(a5, a5, a5);
    peace_sm2_fp_mul(a2, a5, a3);
    peace_sm2_fp_mul(a3, a2, a3);
    peace_sm2_fp_mul(a4, a2, a4);
    for (i = 0; i < 32; i++)
        peace_sm2_fp_mul(a5, a5, a5);
    peace_sm2_fp_mul(r, a4, a5);
}

/**
 * @brief Subtracts b from a modulo N and stores the result in r.
 * @param[in,out] r The result of (a - b) % N, passed as an output parameter.
 * @param[in] a The minuend.
 * @param[in] b The subtrahend.
 */
void peace_sm2_fn_sub(peace_sm2_Fn r, const peace_sm2_Fn a, const peace_sm2_Fn b)
{
    if (peace_sm2_bn_cmp(a, b) >= 0)
    {
        // If a is greater than or equal to b, subtract b from a
        peace_sm2_bn_sub(r, a, b);
    }
    else
    {
        // peace_sm2_BN t;
        //  If a is less than b, add N to a and then subtract b
        peace_sm2_bn_add(tmp, a, peace_sm2_N);
        peace_sm2_bn_sub(r, tmp, b);
    }
}

/**
 * @brief Compares two 288-bit numbers.
 * @param[in] a The first 288-bit number.
 * @param[in] b The second 288-bit number.
 * @return 1 if a > b, -1 if a < b, 0 if a == b.
 */
static int peace_sm2_bn288_cmp(const uint64_t a[9], const uint64_t b[9])
{
    int i;
    for (i = 8; i >= 0; i--)
    {
        if (a[i] > b[i])
            return 1;
        if (a[i] < b[i])
            return -1;
    }
    return 0;
}

/**
 * @brief Adds two 288-bit numbers and stores the result in r.
 * @param[in,out] r The result of a + b, passed as an output parameter.
 * @param[in] a The first 288-bit number.
 * @param[in] b The second 288-bit number.
 */
static void peace_sm2_bn288_add(uint64_t r[9], const uint64_t a[9], const uint64_t b[9])
{
    int i;
    r[0] = a[0] + b[0];
    for (i = 1; i < 9; i++)
    {
        r[i] = a[i] + b[i] + (uint32_t)(r[i - 1] >> 32);
    }
    for (i = 0; i < 8; i++)
    {
        r[i] &= 0xffffffffu;
    }
}

/**
 * @brief Subtracts two 288-bit numbers and stores the result in ret.
 * @param[in,out] ret The result of a - b, passed as an output parameter.
 * @param[in] a The minuend.
 * @param[in] b The subtrahend.
 */
static void peace_sm2_bn288_sub(uint64_t ret[9], const uint64_t a[9], const uint64_t b[9])
{
    int i;
    // uint64_t r[9];

    ret[0] = ((uint64_t)1 << 32) + a[0] - b[0];
    for (i = 1; i < 8; i++)
    {
        ret[i] = 0xffffffffu + a[i] - b[i] + (uint32_t)(ret[i - 1] >> 32);
        ret[i - 1] &= 0xffffffffu;
    }
    ret[i] = a[i] - b[i] + (uint32_t)(ret[i - 1] >> 32) - 1;
    ret[i - 1] &= 0xffffffffu;

    // for (i = 0; i < 9; i++)
    // {
    //    ret[i] = r[i];
    //}
}

/**
 * @brief Multiplies two big numbers and returns the result.
 *
 * This function performs modular multiplication of two large numbers (a, b) and stores the result in ret.
 * The operation is performed modulo n, where n is a predefined constant.
 *
 * @param [out] ret Pointer to the resulting big number.
 * @param [in] a Pointer to the first operand.
 * @param [in] b Pointer to the second operand.
 */
void peace_sm2_fn_mul(peace_sm2_BN ret, const peace_sm2_BN a, const peace_sm2_BN b)
{
    // Temporary variables for intermediate results
   // peace_sm2_BN r;
    static const uint64_t mu[9] = {
        0xf15149a0,
        0x12ac6361,
        0xfa323c01,
        0x8dfc2096,
        1,
        1,
        1,
        1,
        1,
    };

    uint64_t s[18];
    uint64_t zh[9];
    uint64_t zl[9];
    uint64_t q[9];
    uint64_t w;
    int i, j;

    /* Calculate the product z = a * b */
    for (i = 0; i < 8; i++)
    {
        s[i] = 0;
    }
    for (i = 0; i < 8; i++)
    {
        w = 0;
        for (j = 0; j < 8; j++)
        {
            w += s[i + j] + a[i] * b[j];
            s[i + j] = w & 0xffffffffu;
            w >>= 32;
        }
        s[i + 8] = w;
    }

    // Split the product into high and low parts
    for (i = 0; i < 9; i++)
    {
        zl[i] = s[i];
        zh[i] = s[7 + i];
    }

    // Calculate q = zh * mu
    for (i = 0; i < 9; i++)
    {
        s[i] = 0;
    }
    for (i = 0; i < 9; i++)
    {
        w = 0;
        for (j = 0; j < 9; j++)
        {
            w += s[i + j] + zh[i] * mu[j];
            s[i + j] = w & 0xffffffffu;
            w >>= 32;
        }
        s[i + 9] = w;
    }
    for (i = 0; i < 8; i++)
    {
        q[i] = s[9 + i];
    }

    // Reduce q by n
    for (i = 0; i < 17; i++)
    {
        s[i] = 0;
    }
    for (i = 0; i < 8; i++)
    {
        w = 0;
        for (j = 0; j < 8; j++)
        {
            w += s[i + j] + q[i] * peace_sm2_N[j];
            s[i + j] = w & 0xffffffffu;
            w >>= 32;
        }
        s[i + 8] = w;
    }
    for (i = 0; i < 9; i++)
    {
        q[i] = s[i];
    }

    // Calculate r = zl - q (mod (2^32)^9)
    if (peace_sm2_bn288_cmp(zl, q))
    {
        peace_sm2_bn288_sub(zl, zl, q);
    }
    else
    {

        peace_sm2_bn288_sub(q, c, q);
        peace_sm2_bn288_add(zl, q, zl);
    }

    for (i = 0; i < 8; i++)
    {
        ret[i] = zl[i];
    }
    ret[7] += (uint64_t)(zl[8] << 32);

    // Ensure r is less than n
    while (peace_sm2_bn_cmp(ret, peace_sm2_N) >= 0)
    {
        peace_sm2_bn_sub(ret, ret, peace_sm2_N);
    }

    // Copy the result to the output
    //(void)ILib_memcpy(ret, r, PEACE_SM2_sizeof_bn);
}

/**
 * @brief Raises a big number to a power and returns the result.
 *
 * This function raises a big number (a) to the power of another big number (e) and stores the result in r.
 *
 * @param [out] r Pointer to the resulting big number.
 * @param [in] a Pointer to the base.
 * @param [in] e Pointer to the exponent.
 */
void peace_sm2_fn_exp(peace_sm2_BN r, const peace_sm2_BN a, const peace_sm2_BN e)
{
    // peace_sm2_BN t;
    uint32 w;
    int i, j;

    peace_sm2_bn_set_word(tmp, 1);
    for (i = 7; i >= 0; i--)
    {
        w = (uint32)e[i];
        for (j = 0; j < 32; j++)
        {
            peace_sm2_fn_mul(tmp, tmp, tmp);
            if (w & 0x80000000)
            {
                peace_sm2_fn_mul(tmp, tmp, a);
            }
            w <<= 1;
        }
    }
    memcpy(r, tmp, PEACE_SM2_sizeof_bn);
}
/**
 * @brief Generates a random big number within a specified range.
 *
 * This function generates a random big number (r) within the range of 0 to n-1.
 *
 * @param [out] r Pointer to the resulting big number.
 * @return 1 if successful, E_ERROR otherwise.
 */
int peace_sm2_fn_rand(peace_sm2_BN r)
{
    if (peace_sm2_bn_rand_range(r, peace_sm2_N) != 1)
    {
        return E_ERROR;
    }
    return 1;
}


/**
 * @brief Converts a Jacobian point to affine coordinates.
 *
 * This function converts a point from Jacobian coordinates to affine coordinates.
 * If the point is at infinity, the function will handle it accordingly.
 *
 * @param P Pointer to the input Jacobian point.
 * @param x Pointer to the output affine x-coordinate.
 * @param y Pointer to the output affine y-coordinate (optional).
 */
void peace_sm2_jacobian_point_get_xy(const peace_sm2_JACOBIAN_POINT *P, peace_sm2_BN x, peace_sm2_BN y)
{
    if (peace_sm2_bn_is_one(P->Z))
    {
        memcpy(x, P->X, PEACE_SM2_sizeof_bn);
        if (y)
        {
            memcpy(y, P->Y, PEACE_SM2_sizeof_bn);
        }
    }
    else
    {
        // peace_sm2_BN z_inv;
        //(void)ILib_memset(z_inv, 0, PEACE_SM2_sizeof_bn);
        for (uint8 i = 0; i < 8; i++)
        {
            z_inv[i] = 0;
        }

        peace_sm2_fp_inv(z_inv, P->Z);
        if (y)
        {
            peace_sm2_fp_mul(y, P->Y, z_inv);
        }
        peace_sm2_fp_mul(z_inv, z_inv, z_inv);
        peace_sm2_fp_mul(x, P->X, z_inv);
        if (y)
        {
            peace_sm2_fp_mul(y, y, z_inv);
        }
    }
}

/**
 * @brief Checks if a Jacobian point lies on the SM2 elliptic curve.
 *
 * This function verifies whether the given Jacobian point lies on the SM2 elliptic curve.
 * It performs the necessary calculations to check the curve equation.
 *
 * @param P Pointer to the Jacobian point to be checked.
 * @return 1 if the point is on the curve, E_ERROR otherwise.
 */
int peace_sm2_jacobian_point_is_on_curve(const peace_sm2_JACOBIAN_POINT *P)
{

    if (peace_sm2_bn_is_one(P->Z))
    {
        peace_sm2_fp_mul(t0, P->Y, P->Y);
        // peace_sm2_fp_add(t0, t0, P->X);
        // peace_sm2_fp_add(t0, t0, P->X);
        // peace_sm2_fp_add(t0, t0, P->X);
        peace_sm2_bn_add(t0, t0, P->X);
        if (peace_sm2_bn_cmp(t0, peace_sm2_P) >= 0)
        {
            peace_sm2_bn_sub(t0, t0, peace_sm2_P);
        }
        peace_sm2_bn_add(t0, t0, P->X);
        if (peace_sm2_bn_cmp(t0, peace_sm2_P) >= 0)
        {
            peace_sm2_bn_sub(t0, t0, peace_sm2_P);
        }
        peace_sm2_bn_add(t0, t0, P->X);
        if (peace_sm2_bn_cmp(t0, peace_sm2_P) >= 0)
        {
            peace_sm2_bn_sub(t0, t0, peace_sm2_P);
        }
        peace_sm2_fp_mul(t1, P->X, P->X);
        peace_sm2_fp_mul(t1, t1, P->X);
        // peace_sm2_fp_add(t1, t1, peace_sm2_B);
        peace_sm2_bn_add(t1, t1, peace_sm2_B);
        if (peace_sm2_bn_cmp(t1, peace_sm2_P) >= 0)
        {
            peace_sm2_bn_sub(t1, t1, peace_sm2_P);
        }
    }
    else
    {
        peace_sm2_fp_mul(t0, P->Y, P->Y);
        peace_sm2_fp_mul(t1, P->Z, P->Z);
        peace_sm2_fp_mul(t2, t1, t1);
        peace_sm2_fp_mul(t1, t1, t2);
        peace_sm2_fp_mul(t1, t1, peace_sm2_B);
        peace_sm2_fp_mul(t2, t2, P->X);
        // peace_sm2_fp_add(t0, t0, t2);
        // peace_sm2_fp_add(t0, t0, t2);
        // peace_sm2_fp_add(t0, t0, t2);
        peace_sm2_bn_add(t0, t0, t2);
        if (peace_sm2_bn_cmp(t0, peace_sm2_P) >= 0)
        {
            peace_sm2_bn_sub(t0, t0, peace_sm2_P);
        }
        peace_sm2_bn_add(t0, t0, t2);
        if (peace_sm2_bn_cmp(t0, peace_sm2_P) >= 0)
        {
            peace_sm2_bn_sub(t0, t0, peace_sm2_P);
        }
        peace_sm2_bn_add(t0, t0, t2);
        if (peace_sm2_bn_cmp(t0, peace_sm2_P) >= 0)
        {
            peace_sm2_bn_sub(t0, t0, peace_sm2_P);
        }
        peace_sm2_fp_mul(t2, P->X, P->X);
        peace_sm2_fp_mul(t2, t2, P->X);
        // peace_sm2_fp_add(t1, t1, t2);
        peace_sm2_bn_add(t1, t1, t2);
        if (peace_sm2_bn_cmp(t1, peace_sm2_P) >= 0)
        {
            peace_sm2_bn_sub(t1, t1, peace_sm2_P);
        }
    }

    if (peace_sm2_bn_cmp(t0, t1) != 0)
    {
        return E_ERROR;
    }
    return 1;
}

/**
 * @brief Doubles a Jacobian point.
 *
 * This function doubles the given Jacobian point using the addition formula for elliptic curves.
 * If the point is at infinity, it returns the point itself.
 *
 * @param R Pointer to the output Jacobian point.
 * @param P Pointer to the input Jacobian point.
 */
void peace_sm2_jacobian_point_dbl(peace_sm2_JACOBIAN_POINT *R, const peace_sm2_JACOBIAN_POINT *P)
{
    // const uint64_t *X1 = P->X;
    // const uint64_t *Y1 = P->Y;
    // const uint64_t *Z1 = P->Z;

    if (peace_sm2_bn_is_zero(P->Z))
    {
        PEACE_SM2_jacobian_point_copy(R, P);
        return;
    }

    for (uint8 i = 0; i < 8; i++)
    {
        T1[i] = 0;
        T2[i] = 0;
        T3[i] = 0;
        tmp[i] = 0;
    }

    peace_sm2_fp_mul(T1, P->Z, P->Z);
    peace_sm2_fp_sub(T2, P->X, T1);
    // peace_sm2_fp_add(T1, P->X, T1);
    peace_sm2_bn_add(T1, P->X, T1);
    if (peace_sm2_bn_cmp(T1, peace_sm2_P) >= 0)
    {
        peace_sm2_bn_sub(T1, T1, peace_sm2_P);
    }
    peace_sm2_fp_mul(T2, T2, T1);
    // peace_sm2_fp_tri(T2, T2);
    // peace_sm2_fp_add(tmp, T2, T2);
    peace_sm2_bn_add(tmp, T2, T2);
    if (peace_sm2_bn_cmp(tmp, peace_sm2_P) >= 0)
    {
        peace_sm2_bn_sub(tmp, tmp, peace_sm2_P);
    }
    // peace_sm2_fp_add(T2, tmp, T2);
    peace_sm2_bn_add(T2, tmp, T2);
    if (peace_sm2_bn_cmp(T2, peace_sm2_P) >= 0)
    {
        peace_sm2_bn_sub(T2, T2, peace_sm2_P);
    }
    // peace_sm2_fp_add(R->Y, P->Y, P->Y);
    peace_sm2_bn_add(R->Y, P->Y, P->Y);
    if (peace_sm2_bn_cmp(R->Y, peace_sm2_P) >= 0)
    {
        peace_sm2_bn_sub(R->Y, R->Y, peace_sm2_P);
    }
    peace_sm2_fp_mul(R->Z, R->Y, P->Z);
    peace_sm2_fp_mul(R->Y, R->Y, R->Y);
    peace_sm2_fp_mul(T3, R->Y, P->X);
    peace_sm2_fp_mul(R->Y, R->Y, R->Y);
    peace_sm2_fp_div2(R->Y, R->Y);
    peace_sm2_fp_mul(R->X, T2, T2);
    // peace_sm2_fp_add(T1, T3, T3);
    peace_sm2_bn_add(T1, T3, T3);
    if (peace_sm2_bn_cmp(T1, peace_sm2_P) >= 0)
    {
        peace_sm2_bn_sub(T1, T1, peace_sm2_P);
    }
    peace_sm2_fp_sub(R->X, R->X, T1);
    peace_sm2_fp_sub(T1, T3, R->X);
    peace_sm2_fp_mul(T1, T1, T2);
    peace_sm2_fp_sub(R->Y, T1, R->Y);

    //  (void)ILib_memcpy(R->X, X3, PEACE_SM2_sizeof_bn);
    //  (void)ILib_memcpy(R->Y, Y3, PEACE_SM2_sizeof_bn);
    //  (void)ILib_memcpy(R->Z, Z3, PEACE_SM2_sizeof_bn);
}

/**
 * @brief Adds two Jacobian points.
 * @param[out] R Result of the addition.
 * @param[in] P First point to add.
 * @param[in] Q Second point to add.
 * @pre P and Q must be valid Jacobian points.
 * @post R will contain the result of the addition.
 * @return None
 */
void peace_sm2_jacobian_point_add(peace_sm2_JACOBIAN_POINT *R, const peace_sm2_JACOBIAN_POINT *P, const peace_sm2_JACOBIAN_POINT *Q)
{
    // const uint64_t *X1 = P->X;
    //  const uint64_t *Y1 = P->Y;
    //  const uint64_t *Z1 = P->Z;
    //  const uint64_t *x2 = Q->X;
    //  const uint64_t *y2 = Q->Y;

    if (peace_sm2_bn_is_zero(Q->Z))
    {
        PEACE_SM2_jacobian_point_copy(R, P);
        return;
    }

    if (peace_sm2_bn_is_zero(P->Z))
    {
        PEACE_SM2_jacobian_point_copy(R, Q);
        return;
    }

    // assert(peace_sm2_bn_is_one(Q->Z));

    peace_sm2_fp_mul(T1_Add, P->Z, P->Z);
    peace_sm2_fp_mul(T2_Add, T1_Add, P->Z);
    peace_sm2_fp_mul(T1_Add, T1_Add, Q->X);
    peace_sm2_fp_mul(T2_Add, T2_Add, Q->Y);
    peace_sm2_fp_sub(T1_Add, T1_Add, P->X);
    peace_sm2_fp_sub(T2_Add, T2_Add, P->Y);
    if (peace_sm2_bn_is_zero(T1_Add))
    {
        if (peace_sm2_bn_is_zero(T2_Add))
        {
            memset(Q_ADD, 0, sizeof(peace_sm2_JACOBIAN_POINT));
            // peace_sm2_jacobian_point_set_xy(Q_ADD, Q->X, Q->Y);
            memcpy(Q_ADD->X, Q->X, PEACE_SM2_sizeof_bn);
          memcpy(Q_ADD->Y, Q->Y, PEACE_SM2_sizeof_bn);
            peace_sm2_bn_set_word(Q_ADD->Z, 1);

            peace_sm2_jacobian_point_dbl(R, Q_ADD);
            return;
        }
        else
        {
           memset(R, 0, sizeof(peace_sm2_JACOBIAN_POINT));
            R->X[0] = 1;
            R->Y[0] = 1;
            return;
        }
    }
    peace_sm2_fp_mul(R->Z, P->Z, T1_Add);
    peace_sm2_fp_mul(T3_Add, T1_Add, T1_Add);
    peace_sm2_fp_mul(T4_Add, T3_Add, T1_Add);
    peace_sm2_fp_mul(T3_Add, T3_Add, P->X);
    // peace_sm2_fp_add(T1_Add, T3_Add, T3_Add);
    peace_sm2_bn_add(T1_Add, T3_Add, T3_Add);
    if (peace_sm2_bn_cmp(T1_Add, peace_sm2_P) >= 0)
    {
        peace_sm2_bn_sub(T1_Add, T1_Add, peace_sm2_P);
    }

    peace_sm2_fp_mul(R->X, T2_Add, T2_Add);
    peace_sm2_fp_sub(R->X, R->X, T1_Add);
    peace_sm2_fp_sub(R->X, R->X, T4_Add);
    peace_sm2_fp_sub(T3_Add, T3_Add, R->X);
    peace_sm2_fp_mul(T3_Add, T3_Add, T2_Add);
    peace_sm2_fp_mul(T4_Add, T4_Add, P->Y);
    peace_sm2_fp_sub(R->Y, T3_Add, T4_Add);

    // memcpy(R->X, X3_Add, PEACE_SM2_sizeof_bn);
    // memcpy(R->Y, Y3_Add, PEACE_SM2_sizeof_bn);
    // memcpy(R->Z, Z3_Add, PEACE_SM2_sizeof_bn);
}

/**
 * @brief Multiplies a Jacobian point by a scalar.
 * @param[out] R Result of the multiplication.
 * @param[in] k Scalar to multiply by.
 * @param[in] P Point to multiply.
 * @pre P must be a valid Jacobian point.
 * @post R will contain the result of the multiplication.
 * @return None
 */
void peace_sm2_jacobian_point_mul(peace_sm2_JACOBIAN_POINT *R, const peace_sm2_BN k, const peace_sm2_JACOBIAN_POINT *P)
{

    // peace_sm2_JACOBIAN_POINT _Q, *Q = &_Q;
    // peace_sm2_JACOBIAN_POINT _T, *T = &_T;
    int i;
    //(void)ILib_memset(&_Q, 0, sizeof(peace_sm2_JACOBIAN_POINT));
    memset(T, 0, sizeof(peace_sm2_JACOBIAN_POINT));

    if (!peace_sm2_bn_is_one(P->Z))
    {
        for (i = 0; i < 8; i++)
        {
            point_x[i] = 0;
            point_y[i] = 0;
        }

        peace_sm2_jacobian_point_get_xy(P, point_x, point_y);
        // peace_sm2_jacobian_point_set_xy(&_T, point_x, point_y);
        memcpy(T->X, point_x, PEACE_SM2_sizeof_bn);
        memcpy(T->Y, point_y, PEACE_SM2_sizeof_bn);
        peace_sm2_bn_set_word(T->Z, 1);
        P = &_T;
    }

    memset(R, 0, sizeof(peace_sm2_JACOBIAN_POINT));
    R->X[0] = 1;
    R->Y[0] = 1;
    peace_sm2_bn_to_bits(k, bits);
    for (i = 0; i < 256; i++)
    {
        peace_sm2_jacobian_point_dbl(R, R);
        if (bits[i] == '1')
        {
            peace_sm2_jacobian_point_add(R, R, P);
        }
    }

    // (void)ILib_memcpy(R, &_Q, sizeof(peace_sm2_JACOBIAN_POINT));
}

/**
 * @brief Converts a Jacobian point to bytes.
 * @param[in] P Point to convert.
 * @param[out] out Buffer to store the result.
 * @pre P must be a valid Jacobian point.
 * @post out will contain the byte representation of the point.
 * @return None
 */
void peace_sm2_jacobian_point_to_bytes(const peace_sm2_JACOBIAN_POINT *P, uint8 out[64])
{

    peace_sm2_jacobian_point_get_xy(P, point_x, point_y);
    peace_sm2_bn_to_bytes(point_x, out);
    peace_sm2_bn_to_bytes(point_y, out + 32);
}

/**
 * @brief Converts bytes to a Jacobian point.
 * @param[out] P Point to store the result.
 * @param[in] in Buffer containing the byte representation.
 * @pre in must be a valid byte representation of a Jacobian point.
 * @post P will contain the Jacobian point.
 * @return None
 */
void peace_sm2_jacobian_point_from_bytes(peace_sm2_JACOBIAN_POINT *P, const uint8 in[64])
{
    peace_sm2_bn_from_bytes(P->X, in);
    peace_sm2_bn_from_bytes(P->Y, in + 32);
    peace_sm2_bn_set_word(P->Z, 1);
    /* should we check if peace_sm2_jacobian_point_is_on_curve */
}

/**
 * @brief Multiplies the generator point by a scalar.
 * @param[out] R Result of the multiplication.
 * @param[in] k Scalar to multiply by.
 * @pre k must be a valid scalar.
 * @post R will contain the result of the multiplication.
 * @return None
 */
void peace_sm2_jacobian_point_mul_generator(peace_sm2_JACOBIAN_POINT *R, const peace_sm2_BN k)
{
    peace_sm2_jacobian_point_mul(R, k, peace_sm2_G_ptr);
}

/**
 * @brief Computes t * P + s * G.
 * @param[out] R Result of the computation.
 * @param[in] t Scalar to multiply P by.
 * @param[in] P Point to multiply.
 * @param[in] s Scalar to multiply the generator by.
 * @pre P must be a valid Jacobian point.
 * @pre t and s must be valid scalars.
 * @post R will contain the result of the computation.
 * @return None
 */
void peace_sm2_jacobian_point_mul_sum(peace_sm2_JACOBIAN_POINT *R, const peace_sm2_BN t, const peace_sm2_JACOBIAN_POINT *P, const peace_sm2_BN s)
{

    // peace_sm2_BN x;
    // peace_sm2_BN y;
    memset(sG, 0, sizeof(peace_sm2_JACOBIAN_POINT));
    for (uint8 i = 0; i < 8; i++)
    {
        point_x[i] = 0;
        point_y[i] = 0;
    }
    peace_sm2_jacobian_point_mul_generator(sG, s);

    peace_sm2_jacobian_point_mul(R, t, P);
    peace_sm2_jacobian_point_get_xy(R, point_x, point_y);
    // peace_sm2_jacobian_point_set_xy(R, point_x, point_y);
    memcpy(R->X, point_x, PEACE_SM2_sizeof_bn);
    memcpy(R->Y, point_y, PEACE_SM2_sizeof_bn);
    peace_sm2_bn_set_word(R->Z, 1);

    peace_sm2_jacobian_point_add(R, sG, R);
}
/**
 * @brief Checks if a point is on the curve.
 * @param[in] P Point to check.
 * @pre P must be a valid point.
 * @return 1 if the point is on the curve, 0 otherwise.
 */
int peace_sm2_point_is_on_curve(const peace_sm2_POINT *P)
{
    peace_sm2_JACOBIAN_POINT T;
    peace_sm2_jacobian_point_from_bytes(&T, (const uint8_t *)P);
    return peace_sm2_jacobian_point_is_on_curve(&T);
}
